package com.xuecheng.ucenter.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.ucenter.mapper.XcMenuMapper;
import com.xuecheng.ucenter.mapper.XcUserMapper;
import com.xuecheng.ucenter.model.dto.AuthParamsDto;
import com.xuecheng.ucenter.model.dto.XcUserExt;
import com.xuecheng.ucenter.model.po.XcMenu;
import com.xuecheng.ucenter.model.po.XcUser;
import com.xuecheng.ucenter.service.AuthService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.function.IntFunction;
import java.util.stream.Collectors;

/**
 * @Author xiao
 * @Date 2024/12/22 下午 9:01
 * @ClassName: UserDetailsServiceImpl
 * @Description: 重写UserServiceImpl实现自定义用户认证方法
 *               UserDetailsService用来管理 Spring Security 静态内部类User的用户信息
 */
@Slf4j
@Component
public class UserServiceImpl implements UserDetailsService {

    @Resource
    private XcUserMapper xcUserMapper;
    @Resource
    private AuthService authService;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private XcMenuMapper xcMenuMapper;


    // 比对传入对象   参数s->输入的username中的Json数据
    // 这个方法是拿到传入的对象

    /**
     * 现在这个方法为将传入的username->json数据转为AuthParamsDto对象，并且根据认证方式调用不同的认证接口
     * 这个方法不再作为返回用户对象使用
     */
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        AuthParamsDto authParamsDto = null;
        //将输入的json转为对象
        try {
            authParamsDto = JSON.parseObject(s, AuthParamsDto.class);
        } catch (Exception e) {
            log.info("认证请求不符合项目要求:{}", s);
            throw new RuntimeException("认证请求数据格式不对");
        }

        //获取认证类型
        String authType = authParamsDto.getAuthType();
        //根据类型获取Bean
        String benaName = authType + "_authservice";
        AuthService authService = applicationContext.getBean(benaName, AuthService.class);
        //调用统一认证方法，开始认证
        XcUserExt user = authService.execute(authParamsDto);
        //封装 XcUserExt 为userDetail

        /*
        已经在 authService.execute实现了，
        根据username查询用户
        String username = authParamsDto.getUsername();
        XcUser xcUser = xcUserMapper.selectOne(new LambdaQueryWrapper<XcUser>().eq(XcUser::getUsername, username));
        //查询不到 返回null
        if (xcUser == null) {
            return null;
        }*/
        //查询到，拿到正确密码，封装为UserDetails对象 返回给框架，由框架进行比对
        return getUserPricncipal(user);
    }

    private UserDetails getUserPricncipal(XcUserExt user) {
        String password = user.getPassword();
        //权限:从数据库查询并封装
        String[] authorities = null;
        List<XcMenu> xcMenus = xcMenuMapper.selectPermissionByUserId(user.getId());
        if (xcMenus.size() <= 0) {
            authorities[0] = "p1";
        } else {
            //通过Stream流转为List集合
            List<String> permission = xcMenus.stream()
                    .map(XcMenu::getCode)
                    .collect(Collectors.toList());
            //将权限信息放入 XcUserExt 对象中,目前没有使用
            //放入username.Permissions
            user.setPermissions(permission);
            //放入框架的权限认证 转数组
            authorities = permission.toArray(new String[0]);
        }
        //用户密码置空
        user.setPassword(null);
        //转JSON
        String json = JSON.toJSONString(user);

        //返回UserDetails对象，使用Jwt令牌在username中存入自定义数据
        return User.withUsername(json)
                .password(password)
                .authorities(authorities)
                .build();
    }
}
